package com.goldman.aplt.base.interceptor;

import com.goldman.aplt.base.constant.ApConstants;
import com.goldman.aplt.base.constant.HeaderConst;
import com.goldman.aplt.base.type.BaseEnumType;
import com.goldman.aplt.base.type.Header;
import com.goldman.aplt.base.type.TrxnEnvs;
import com.goldman.aplt.util.*;
import com.goldman.base.common.sys.filter.AccessRequestWrapper;
import com.goldman.http.common.s2s.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.Stack;

/**
 * 业务交易拦截器
 */
@Slf4j
public class BusiTrxnInterceptor implements HandlerInterceptor {
    @Resource
    private StringRedisTemplate strRedisTmpl;

    @Value("${systemId}")
    private String systemId;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String system = systemId;
        //企业网银系统id特殊处理
        if(request.getServletPath().startsWith("/cb")) {
            system = BaseEnumType.E_SYSTEM_ID.GCB.getValue();
        }

        //初始化公共运行区数据
        initTrxnEnv(request, system);
        Object[] objs = new Object[]{system, request.getServletPath(), request.getRequestURL(),  CommUtil.getTrxnEnvs().getTrxn_seq(),
                CommUtil.getTrxnEnvs().getBusi_seq(), CommUtil.getComputerDate()+" "+CommUtil.getComputerTime()};
        String logFormat = "[{}{} tran process start] url={} trxnSeq={} busiSeq={} beginTime={}";
        log.info(logFormat, objs);
        return true;
    }

    private void initTrxnEnv(HttpServletRequest request, String system) {
        TrxnEnvs trxnEnvs = CommUtil.getTrxnEnvs();
        String servletPath = request.getServletPath();
        //触发交易的时间
        trxnEnvs.setComputer_date(CommUtil.getComputerDate());
        trxnEnvs.setTrxn_date(CommUtil.getComputerDate());
        trxnEnvs.setComputer_time(CommUtil.getComputerTime());
        trxnEnvs.setApp_token(request.getHeader(HeaderConst.TOKEN_HEADER));
        trxnEnvs.setSystem_id(system);
        String ip = "";
        if(CommUtil.isNotNull(request.getHeader(HeaderConst.CLIENT_IP))) {
            ip = request.getHeader(HeaderConst.CLIENT_IP);
        } else {
            ip = NetUtil.getClientIP(request);
            if(CommUtil.isNotNull(ip) && ip.contains(",")) {
                ip = ip.split(",")[0];
            }
        }
        //给header赋值
        Header header = Header.builder()
                .uid(request.getHeader(HeaderConst.UID_HEADER))
                .token(request.getHeader(HeaderConst.TOKEN_HEADER))
                .xRequestId(request.getHeader(HeaderConst.REQUEST_ID_HEADER))
                .sign(request.getHeader(HeaderConst.SIGN_HEADER))
                .deviceId(request.getHeader(HeaderConst.DEVICE_ID_HEADER))
                .deviceFingerPrint(request.getHeader(HeaderConst.DEVICE_FINGER_PRINT_HEADER))
                .gaid(request.getHeader(HeaderConst.GAID_HEADER))
                .idfa(request.getHeader(HeaderConst.IDFA_HEADER))
                .publishChannel(request.getHeader(HeaderConst.PULISH_CHANNEL_HEADER))
                .installChannel(request.getHeader(HeaderConst.INSTALL_CHANNEL_HEADER))
                .adsCampaign(request.getHeader(HeaderConst.ADS_CAMPAIGN_HEADER))
                .countryCode(request.getHeader(HeaderConst.COUNTRY_CODE_HEADER))
                .systemVersion(request.getHeader(HeaderConst.SYSTEM_VERSION_HEADER))
                .phoneModel(request.getHeader(HeaderConst.PHONE_MODEL_HEADER))
                .xPackageName(request.getHeader(HeaderConst.PACKAGE_NAME_HEADER))
                .xAppVercode(request.getHeader(HeaderConst.APP_VERCODE_HEADER))
                .xAppVerName(request.getHeader(HeaderConst.APP_VERNAME_HEADER))
                .xCurrentTime(request.getHeader(HeaderConst.CURRENT_TIME_HEADER))
                .clientIp(ip)
                .phoneBrand(request.getHeader(HeaderConst.PHONE_BRAND_HEADER))
                .build();
        trxnEnvs.setHeader(header);
        CommUtil.setTrxnEnvs(trxnEnvs);
        String trxnSeq = ApSeqUtil.genSeq(ApConstants.TRXN_SEQ_CODE);
        //生成交易流水
        trxnEnvs.setTrxn_seq(trxnSeq);
        //生成业务流水
        trxnEnvs.setBusi_seq(getBusiSeq(request, trxnSeq));
        //交易路径
        trxnEnvs.setTrxn_code(servletPath);

        String ruleKye = request.getHeader(HeaderConst.RULE_BUFFER);
        if(CommUtil.isNotNull(ruleKye)) {
            String jruleBuffer = strRedisTmpl.opsForValue().get(ruleKye);
            strRedisTmpl.delete(ruleKye);
            Stack<Map<String, Object>> ruleBufferStack = new Stack<Map<String, Object>>();
            ruleBufferStack.push(JsonUtil.toMap(jruleBuffer));
            trxnEnvs.setRule_buffer(ruleBufferStack);
        } else {
            //默认将request请求放入INPUT规则数据集
            AccessRequestWrapper wrapperRequest = new AccessRequestWrapper(request);
            String body = extractRequest(wrapperRequest);
            String contentType = request.getHeader("content-type");
            if(CommUtil.isNotNull(contentType)
                    && contentType.contains("application/json")
                    && !body.startsWith("[")) {
                ApBuffer.appendData(ApConstants.INPUT_DATA_MART, JsonUtil.toMap(body));
            }
        }

        CommUtil.setTrxnEnvs(trxnEnvs);
    }

    private String getBusiSeq(HttpServletRequest request, String trxnSeq) {
        String busiSeq = trxnSeq;
        if(CommUtil.isNotNull(request.getParameter("busi_seq"))) {
            busiSeq = request.getParameter("busi_seq");
        } else if(CommUtil.isNotNull(request.getHeader(HeaderConst.BUSI_SEQ))) {
            busiSeq = request.getHeader(HeaderConst.BUSI_SEQ);
        } else if(CommUtil.isNotNull(request.getHeader(HeaderConst.REQUEST_ID_HEADER))) {
            busiSeq = request.getHeader(HeaderConst.REQUEST_ID_HEADER);
        }
        return busiSeq;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        Object[] objs = new Object[]{CommUtil.getTrxnEnvs().getSystem_id(), request.getServletPath(), request.getRequestURL(),  CommUtil.getTrxnEnvs().getTrxn_seq(),
                CommUtil.getTrxnEnvs().getBusi_seq(), CommUtil.formatDateTime(new Date()), response.getStatus()};
        String logFormat = "[{}{} tran process end] url={} trxnSeq={} busiSeq={} endTime={} tranStatus={}";
        log.info(logFormat, objs);
        //TODO 登记aps_packet表
        TrxnContext.getInstance().clear();
    }

    private String extractRequest(AccessRequestWrapper request) {
        if (null != request && !request.getRequestURI().contains("swagger")) {
            try {
                String body = IOUtils.toString(request.getInputStream());
                return body;
            } catch (IOException e) {
                log.error("处理请求日志失败: ", e);
            }
        }
        return "";
    }

}
